using System;
using System.Collections.Generic;
using Me.Prettyprint.Cassandra.Model;
using Me.Prettyprint.Cassandra.Model.Thrift;
using Me.Prettyprint.Cassandra.Serializers;
using Me.Prettyprint.Cassandra.Service;
using Me.Prettyprint.Cassandra.Utils;
using Me.Prettyprint.Hector.Api;
using Me.Prettyprint.Hector.Api.Beans;
using Me.Prettyprint.Hector.Api.Factory;
using Me.Prettyprint.Hector.Api.Mutation;
using Thrift;

namespace Me.Prettyprint.Cassandra.Service.Template
{
    /// <summary>
    /// Provides access to the current row of data during queries. There is a lot of
    /// overlap in needs for both standard and super queries. This class consolidates
    /// what they have in common. All data is read into ByteBuffers and translated to
    /// a primitive type when requested.
    /// 
    /// This class is a non-static inner class which inherits the Java generic
    /// parameters of it's containing ColumnFamilyTemplate instance. This allows it to
    /// inherit the <K> parameter from ColumnFamilyTemplate.
    /// 
    /// The <N> parameters allows this to be used by standard and super column
    /// queries
    /// </summary>
    /// <typeparam name="K">the type of the key</typeparam>
    /// <typeparam name="N">the standard column name type or the super column's child column type</typeparam>
	public abstract class AbstractResultWrapper<K,N> : ColumnFamilyResult<K, N>
	{
        public AbstractResultWrapper(Serializer<K> keySerializer, Serializer<N> columnNameSerializer, ResultStatus resultStatus)
        {
            KeySerializer = keySerializer;
            ColumnNameSerializer = columnNameSerializer;
            ResultStatus = resultStatus;
        }
        protected Serializer<K> KeySerializer
        {
            get;
            set;
        }
        protected Serializer<N> ColumnNameSerializer
        {
            get;
            set;
        }
        protected ResultStatus ResultStatus
        {
            get;
            set;
        }
        public K Key
        {
            get;
            protected set;
        }
        public bool HasResults
        {
            get;
            protected set;
        }
        public abstract ByteBuffer GetColumnValue(N columnName);

        public virtual Guid GetUUID(N columnName)
        {
            return UUIDSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual string GetString(N columnName)
        {
            return StringSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual long GetLong(N columnName)
        {
            return LongSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual int GetInteger(N columnName)
        {
            return IntegerSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual float GetFloat(N columnName)
        {
            return FloatSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual double GetDouble(N columnName)
        {
            return DoubleSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual bool GetBoolean(N columnName)
        {
            return BooleanSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual byte[] GetByteArray(N columnName)
        {
            return BytesArraySerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public virtual DateTime GetDate(N columnName)
        {
            return DateSerializer.Instance.FromByteBuffer(GetColumnValue(columnName));
        }
        public long ExecutionTimeMicro
        {
            get
            {
                return ResultStatus.ExecutionTimeMicro;
            }
        } 
        public long ExecutionTimeNano
        {
            get
            {
                return ResultStatus.ExecutionTimeNano;
            }
        }
        public CassandraHost HostUsed
        {
            get
            {
                return ResultStatus.HostUsed;
            }
        }
        public abstract List<N> GetColumnNames();
        public abstract HColumn<N, byte[]> GetColumn(N columnName);
        public abstract bool HasNext();
        /// <summary>
        /// Subclasses must implement this method. The method currently returns null so that
        /// SuperCfResultWrapper can override it. We can't make it abstract due to how how
        /// generics works in C#. 
        /// </summary>
        /// <returns></returns>
        public virtual ColumnFamilyResult<K, N> Next()
        {
            return null;
        }
	}
}